home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / ftpser1a / ftp_srv.bas < prev    next >
Encoding:
BASIC Source File  |  1999-10-04  |  13.0 KB  |  453 lines

  1. Attribute VB_Name = "FTP_SRV1"
  2.  
  3. Global sintax_error_list(10) As String 'the list of the messagges which signal a sintax error in a FTP command
  4.  
  5.  
  6. Type user
  7.   'indexes user name and password inside
  8.   '<usernames_list> and <passwords_list> arrays
  9.   list_index As Integer
  10.   control_slot As Long 'slot number used by client to send commands to server. On this slot also travel the replies of server.
  11.   data_slot As Long    'slot number used by server to send data to client
  12.   IP_address As String 'client IP address
  13.   Port As Integer      'number of client data port
  14.   'representation type to use for data
  15.   'encoding (ex. ASCII o EBCDIC), default type is A (= ASCII)
  16.   data_representation As String * 1
  17.   'type of vertical format control
  18.   '(ie. line-feed, form-feed), default
  19.   'value is N (No print = no command)
  20.   data_format_ctrls As String * 1
  21.   'file structure (ex. File-structure, Record-structure),
  22.   'default value is F (File-structure = no internal
  23.   'structure)
  24.   data_structure As String * 1
  25.   'indicates if the data are processing before
  26.   'transmission (ex. Stream-mode, Block-mode),
  27.   'default value is S (Stream-mode = no
  28.   'processing)
  29.   data_tx_mode As String * 1
  30.   'current working directory
  31.   cur_dir As String
  32.   'user state:
  33.   'in state 0 the user sends access control commands;
  34.   'in state 1 the user sends transfer parameter commands;
  35.   'in state 2 the user sends FTP service commands.
  36.   state As Integer
  37.   full As Integer  'if true the record is already in use
  38.   temp_data As String  'contains temporary data
  39. End Type
  40. Global users(MAX_N_USERS) As user
  41.  
  42. Type file_info
  43.   Full_Name As String
  44.   data_representation As String * 1
  45.   open_file As Integer
  46.   retr_stor As Integer  '0=RETR; 1=STOR
  47.   Buffer As String  'contains data to send
  48.   File_Len As Long  '--- Binary mode only
  49.   blocks As Long  'number of 1024 bytes blocks in file
  50.   spare_bytes As Long
  51.   next_block As Long  'next block to send
  52.   next_byte As Long  'points to position in file of the next block to send
  53.   try_again As Integer  'if try_again=true the old line is sent =Ascii mode only
  54. End Type
  55. Global files_info(5) As file_info
  56.  
  57. 'contains error during function call
  58. Global retf As Integer
  59.  
  60. '*** Variables used during TCP/IP exchange
  61. 'slot number assigned to Server
  62. Global ServerSlot As Long
  63. 'number of clients connected to server
  64. Global num_users As Integer
  65. Global ListenSock As Long
  66. Global NewSlot As Long
  67.  
  68. Function args_ctrl(ArgS As String, Type_Args As String, ByRef Argument() As String) As Integer
  69. Dim Dummy As String
  70. Dim len_args As Integer, i As Integer, ascii As Integer
  71. Dim s As Integer, e As Integer
  72. ReDim h(6) As Long
  73.  
  74. 'the arguments of type <username>, <password> and
  75. '<pathname> are strings
  76. If Type_Args = "username" Or Type_Args = "password" _
  77. Or Type_Args = "pathname" Then
  78.   Type_Args = "string"
  79. End If
  80.  
  81. 'command Ok
  82. args_ctrl = 0
  83.  
  84. len_args = Len(ArgS)
  85.  
  86. Select Case Type_Args
  87.   
  88.   Case "string": '<string>  <string:= char | char&string>
  89.     For i = 1 To len_args
  90.       ascii = Asc(Mid$(ArgS, i, 1))
  91.       If ascii < 32 Or ascii > 126 Then      'only printable characters
  92.         args_ctrl = 3           'sintax error in parameters or arguments
  93.         Exit For
  94.       End If
  95.     Next
  96.     Argument(0) = ArgS
  97.  
  98.   Case "host-port": '<h1,h2,h3,h4,p1,p2>  <h?:=1..255>  <p?:=1..255>
  99.     '<Host> is formed by 4 elements, divided by comma, which representing IP address;
  100.     '<port> is formed by 2 elements, divided by comma, which representing the MSB and LSB of the port.
  101.     'add a separator for simplifing the procedure
  102.     Dummy = ArgS & ","
  103.     Debug.Print "Port String = " & Dummy
  104.     e = 1    'point to next element
  105.     For i = 1 To 6
  106.       s = InStr(e, Dummy, ",") 's point to next separator (ie. comma)
  107.       If s = 0 Then
  108.         args_ctrl = 3          'sintax error in parameters or arguments
  109.         Exit For
  110.       Else
  111.         'every element of the argument must be an integer,
  112.         'represented as string, in the range 1 to 255
  113.         h(i) = Val(Mid$(Dummy, e, s - e))
  114.         Debug.Print "h(" & CStr(i) & ") = " & h(i)
  115.         If h(i) < 0 Or h(i) > 255 Then
  116.           args_ctrl = 3       'sintax error in parameters or arguments
  117.           Exit For
  118.         End If
  119.       End If
  120.       e = s + 1       'point to next element
  121.     Next
  122.     Argument(0) = Format$(h(1))              'IP address
  123.     Argument(1) = Format$(h(2))
  124.     Argument(2) = Format$(h(3))
  125.     Argument(3) = Format$(h(4))
  126.     Argument(4) = Format$(h(5) * 256 + h(6)) 'port
  127.   
  128.   Case "type-code":  '<A [A N] | I>
  129.   S1 = InStr(ArgS, " ")
  130.   If S1 = 0 Then
  131.     If ArgS = "A" Or ArgS = "" Then
  132.       'arguments assume default values
  133.       Argument(0) = "A"  'Ascii
  134.       Argument(1) = "N"  'No print
  135.     ElseIf ArgS = "E" Then
  136.       'command not implemented for that parameter
  137.       args_ctrl = 6
  138.       Argument(0) = ArgS
  139.     ElseIf ArgS = "I" Then
  140.       Argument(0) = "I"
  141.     Else
  142.       'sintax error in parameters or arguments
  143.       args_ctrl = 3
  144.       Argument(0) = ArgS
  145.     End If
  146.   Else
  147.     If Left$(ArgS, S1 - 1) = "A" Then
  148.       Argument(0) = "A"
  149.       While Mid$(ArgS, S1, 1) = " "
  150.         S1 = S1 + 1
  151.       Wend
  152.       If Mid$(ArgS, S1) = "" Or Mid$(ArgS, S1) = "N" Then
  153.         Argument(1) = "N"
  154.       ElseIf Mid$(ArgS, S1) = "T" Then
  155.         'command not implemented for that parameter
  156.         args_ctrl = 6
  157.         Argument(1) = Mid$(ArgS, S1)
  158.       ElseIf Mid$(ArgS, S1) = "C" Then
  159.         'command not implemented for that parameter
  160.         args_ctrl = 6
  161.         Argument(1) = Mid$(ArgS, S1)
  162.       Else
  163.         'sintax error in parameters or arguments
  164.         args_ctrl = 3
  165.         Argument(1) = Mid$(ArgS, S1)
  166.       End If
  167.     ElseIf Left$(ArgS, S1 - 1) = "L" Then
  168.       'command not implemented for that parameter
  169.       args_ctrl = 6
  170.       Argument(1) = Mid$(ArgS, S1)
  171.     ElseIf Left$(ArgS, S1 - 1) = "I" Then
  172.       Argument(0) = "I"
  173.     Else
  174.       'sintax error in parameters or arguments
  175.       args_ctrl = 3
  176.       Argument(0) = Left$(ArgS, S1 - 1)
  177.     End If
  178.   End If
  179.  
  180.   Case "mode-code":  '<S>
  181.   If ArgS = "" Or ArgS = "S" Then
  182.     'argument assumes default value
  183.     Argument(0) = "S"  'Stream
  184.   ElseIf ArgS = "B" Then
  185.     'command not implemented for that parameter
  186.     args_ctrl = 6
  187.     Argument(0) = ArgS
  188.   ElseIf ArgS = "C" Then
  189.     'command not implemented for that parameter
  190.     args_ctrl = 6
  191.     Argument(0) = ArgS
  192.   Else
  193.     'sintax error in parameters or arguments
  194.     args_ctrl = 3
  195.     Argument(0) = Left$(ArgS, S1 - 1)
  196.   End If
  197.  
  198.   Case "structure-code":  '<F | R>
  199.   If ArgS = "" Or ArgS = "F" Then
  200.     'argument assumes default value
  201.     Argument(0) = "F" 'File
  202.   ElseIf ArgS = "R" Then
  203.     'command not implemented for that parameter
  204.     args_ctrl = 6
  205.     Argument(0) = ArgS
  206.   ElseIf ArgS = "P" Then
  207.     'command not implemented for that parameter
  208.     args_ctrl = 6
  209.     Argument(0) = ArgS
  210.   Else
  211.     'sintax error in parameters or arguments
  212.     args_ctrl = 3
  213.     Argument(0) = ArgS
  214.   End If
  215.   
  216. End Select
  217.  
  218. End Function
  219.  
  220. Function close_data_connect(Id_User As Integer) As Integer
  221.   
  222.   retf = closesocket(users(Id_User).data_slot)
  223.   If retf = 0 Then
  224.     'updates user record
  225.     users(Id_User).data_slot = INVALID_SOCKET
  226.     users(Id_User).IP_address = ""
  227.     users(Id_User).Port = 0
  228.     users(Id_User).state = 2
  229.   End If
  230.   close_data_connect = retf
  231.  
  232. End Function
  233.  
  234. Function logoff(Id_User As Integer) As Integer
  235.  
  236.   retf = send_reply("221 Closing control connection, GoodBye!", Id_User)
  237.   retf = closesocket(users(Id_User).control_slot)
  238.   If retf = 0 Then
  239.     're-initialize the record containing user informations
  240.     users(Id_User).list_index = 0
  241.     users(Id_User).control_slot = INVALID_SOCKET
  242.     users(Id_User).data_slot = INVALID_SOCKET
  243.     users(Id_User).IP_address = ""
  244.     users(Id_User).Port = 0
  245.     users(Id_User).data_representation = "A"
  246.     users(Id_User).data_format_ctrls = "N"
  247.     users(Id_User).data_structure = "F"
  248.     users(Id_User).data_tx_mode = "S"
  249.     users(Id_User).cur_dir = ""
  250.     users(Id_User).state = 0
  251.     users(Id_User).full = False
  252.   Else
  253.     FtpServ.StatusBar.Panels(1) = "Error: Couldn't Close Connection!"
  254.   End If
  255.   num_users = num_users - 1
  256.   FtpServ.UsrCnt = CStr(num_users)
  257.   logoff = retf
  258.  
  259. End Function
  260.  
  261. Function open_data_connect(Id_User As Integer) As Integer
  262.   
  263.   'open data connection
  264.   retf = send_reply("150 Open data connection.", Id_User)
  265.   open_data_connect = retf
  266.  
  267. End Function
  268.  
  269. Function receive_data(RecvBuffer As String, Id_User As Integer) As Integer
  270. Dim fixstr As String * 1024
  271.  
  272.   'receives data on connection
  273.   retf = recv(users(Id_User).data_slot, fixstr, 1024, 0)
  274.   If retf > 0 Then
  275.     RecvBuffer = Left$(fixstr, retf)
  276.   End If
  277.   receive_data = retf
  278.  
  279. End Function
  280.  
  281. Function send_data(data_ As String, Id_User As Integer) As Integer
  282. 'write buffer
  283. Dim WriteBuffer As String
  284. 'write buffer lenght
  285. Dim lenBuffer As Integer
  286.  
  287.   'sends data on connection
  288.   WriteBuffer = data_
  289.   lenBuffer = Len(WriteBuffer)
  290.   retf = send(users(Id_User).data_slot, WriteBuffer, lenBuffer, 0)
  291.   send_data = retf
  292.  
  293. End Function
  294.  
  295. Function send_reply(reply As String, Id_User As Integer) As Integer
  296. Dim WriteBuffer As String
  297. Dim lenBuffer As Integer 'buffer lenght
  298.  
  299.   'sends reply to user <id_user>
  300.   WriteBuffer = reply & vbCrLf
  301.   lenBuffer = Len(WriteBuffer)
  302.   retf = send(users(Id_User).control_slot, WriteBuffer, lenBuffer, 0)
  303.   If retf = SOCKET_ERROR Then
  304.     ServerLog "Error sending reply:" & CStr(retf)
  305.   Else
  306.     'log replies
  307.     ServerLog "<" & Format$(Id_User, "000") & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm - ") & reply
  308.   End If
  309.   send_reply = retf
  310.  
  311. End Function
  312.  
  313. Function sintax_ctrl(cmd As String, ByRef Kwrd As String, ByRef Argument() As String) As Integer
  314. Dim ArgS As String
  315. Dim k As Integer
  316.  
  317. 'the command must be terminated by CR&LF characters
  318. len_cmd = InStr(cmd, vbCrLf) - 1
  319. If len_cmd = 0 Then
  320.   sintax_ctrl = 2 'sintax error, command unrecognized
  321.   Exit Function
  322. Else
  323.   'suppresses CR&LF characters
  324.   cmd = Left$(cmd, len_cmd)
  325. End If
  326.  
  327. 'extract keyword
  328. k = InStr(cmd, " ")
  329. If k <> 0 Then
  330.   'command with arguments
  331.   Kwrd = Left$(cmd, k - 1)  'keyword
  332.   While Mid$(cmd, k, 1) = " "
  333.    k = k + 1
  334.   Wend
  335.   ArgS = Mid$(cmd, k)       'arguments
  336. Else
  337.   'command without arguments
  338.   Kwrd = cmd
  339.   ArgS = ""
  340. End If
  341.  
  342. 'command Ok
  343. sintax_ctrl = 0
  344.  
  345. Select Case UCase$(Kwrd)
  346.   
  347.   Case "USER":  'USER <username>
  348.   sintax_ctrl = args_ctrl(ArgS, "username", Argument())
  349.   
  350.   Case "PASS": 'PASS <password>
  351.   sintax_ctrl = args_ctrl(ArgS, "password", Argument())
  352.  
  353.   Case "ACCT":
  354.   sintax_ctrl = 4 'command not implemented
  355.   
  356.   Case "CWD", "XCWD": 'CWD <pathname>
  357.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  358.   
  359.   Case "CDUP", "XCUP":  'CDUP
  360.   '------------------
  361.  
  362.   Case "SMNT":
  363.   sintax_ctrl = 4 'command not implemented
  364.  
  365.   Case "QUIT": 'QUIT
  366.   '-----------------
  367.  
  368.   Case "REIN": 'REIN
  369.   sintax_ctrl = 4 'command not implemented
  370.  
  371.   Case "PORT": 'PORT <host-port>
  372.   sintax_ctrl = args_ctrl(ArgS, "host-port", Argument())
  373.  
  374.   Case "PASV":
  375.   sintax_ctrl = 4 'command not implemented
  376.  
  377.   Case "TYPE": 'TYPE <type-code>
  378.   sintax_ctrl = args_ctrl(ArgS, "type-code", Argument())
  379.  
  380.   Case "STRU": 'STRU <structure-code>
  381.   sintax_ctrl = args_ctrl(ArgS, "structure-code", Argument())
  382.   
  383.   Case "MODE": 'MODE <mode-code>
  384.   sintax_ctrl = args_ctrl(ArgS, "mode-code", Argument())
  385.   
  386.   Case "RETR": 'RETR <pathname>
  387.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  388.   
  389.   Case "STOR": 'STOR <pathname>
  390.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  391.  
  392.   Case "STOU":
  393.   sintax_ctrl = 4 'command not implemented
  394.  
  395.   Case "APPE":
  396.   sintax_ctrl = 4 'command not implemented
  397.  
  398.   Case "ALLO":
  399.   sintax_ctrl = 1 'command not implemented, superfluous at this side
  400.  
  401.   Case "REST":
  402.   sintax_ctrl = 4 'command not implemented
  403.   
  404.   Case "RNFR":  'RNFR <pathname>
  405.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  406.   
  407.   Case "RNTO":  'RNTO <pathname>
  408.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  409.   
  410.   Case "ABOR":
  411.   sintax_ctrl = 4 'command not implemented
  412.   
  413.   Case "DELE":  'DELE <pathname>
  414.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  415.   
  416.   Case "RMD", "XRMD": 'RMD <pathname>
  417.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  418.  
  419.   Case "MKD", "XMKD": 'MKD <pathname>
  420.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  421.  
  422.   Case "PWD", "XPWD": 'PWD
  423.   '----------------
  424.  
  425.   Case "LIST": 'LIST <pathname>
  426.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  427.   
  428.   Case "NLST": 'NLST <pathname>
  429.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  430.   
  431.   Case "SITE":
  432.   sintax_ctrl = 4 'command not implemented
  433.  
  434.   Case "SYST":  'SYST
  435.   '------------------
  436.  
  437.   Case "STAT":  'STAT <pathname>
  438.   sintax_ctrl = args_ctrl(ArgS, "pathname", Argument())
  439.  
  440.   Case "HELP":  'HELP <string>
  441.   sintax_ctrl = args_ctrl(ArgS, "string", Argument())
  442.   
  443.   Case "NOOP": 'NOOP
  444.   '-----------------
  445.  
  446.   Case Else
  447.   sintax_ctrl = 2 'sintax error, command unrecognized
  448.  
  449. End Select
  450.  
  451. End Function
  452.  
  453.